package edu.luc.etl.jbunit.tl;

import java.util.ArrayList;
import java.util.List;

/**
 * The formula <code>l /\ r</code> specifies that
 * both <code>l</code> and <code>r</code> must be true in the
 * current time unit.
 */

public class And<T> extends Expr<T> {

  private List<Expr<T>> exprs;

  public And(List<Expr<T>> exprs) {
    this.exprs = exprs;
  }
  
  // TODO consider moving to a Util class
  
  public static <T> List<Expr<T>> toExprList(List<T> values) {
    List<Expr<T>> result = new ArrayList<Expr<T>>(values.size());
    for (T v : values) {
      result.add(new Leaf<T>(v));
    }
    return result;
  }
  
  // TODO consider moving to a Util class
  
  protected static <T> List<Expr<T>> toList(Expr<T> l, Expr<T> r) {
    List<Expr<T>> result = new ArrayList<Expr<T>>(2);
    result.add(l);
    result.add(r);
    return result;
  }
  
  public And(Expr<T> l, Expr<T> r) {
    this(toList(l, r));
  }

  public And(T l, T r) {
    this(new Leaf<T>(l), new Leaf<T>(r));
  }

  public And(Expr<T> l, T r) {
    this(l, new Leaf<T>(r));
  }

  public And(T l, Expr<T> r) {
    this(new Leaf<T>(l), r);
  }

  public And<T> clone() {
    And<T> result = (And<T>) super.clone();
    result.exprs = new ArrayList<Expr<T>>(exprs.size());
    for (Expr<T> e : exprs) {
      result.exprs.add(e.clone());
    }
    return result;
  }

  public void reset () {  
    for (Expr<T> e : exprs) {
      e.reset();
    }
  }
  
  public void tick () { 
    evaluated = false; 
    for (Expr<T> e : exprs) {
      e.tick();
    }
  }

  boolean ev () {
    val = true;
    for (Expr<T> e : exprs) {
      val = val && e.valuate();
    }
    return val;
  }

  void accept(Visitor<T> v) {
    v.visitAnd(this);
    for (Expr<T> e : exprs) {
      e.accept(v);
    }
  }
}
